home *** CD-ROM | disk | FTP | other *** search
/ The X-Philes (2nd Revision) / The X-Philes Number 1 (1995).iso / xphiles / hp95 / freyja_t.z / freyja_t / date.c < prev    next >
C/C++ Source or Header  |  1992-04-14  |  9KB  |  426 lines

  1. /* DATE.C -- Calendar Routines
  2.  
  3.     Written June 1991 by Craig A. Finseth
  4.     Copyright 1991 by Craig A. Finseth
  5. */
  6.  
  7. #include "freyja.h"
  8. #if defined(MSDOS)
  9. #include <time.h>
  10. time_t time();
  11. struct tm *localtime();
  12. #endif
  13.  
  14. #define SYS_CAL        "%cal%"
  15. #define CAL_WIDTH    35
  16.  
  17.     /* Cumulative month start day number.  Yes, I know this has 13
  18.     months. */
  19. static int mdays[] = {
  20.     0,
  21.     0 + 31,
  22.     0 + 31 + 28,
  23.     0 + 31 + 28 + 31,
  24.     0 + 31 + 28 + 31 + 30,
  25.     0 + 31 + 28 + 31 + 30 + 31,
  26.     0 + 31 + 28 + 31 + 30 + 31 + 30,
  27.     0 + 31 + 28 + 31 + 30 + 31 + 30 + 31,
  28.     0 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
  29.     0 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
  30.     0 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
  31.     0 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
  32.     0 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 };
  33.  
  34. static char *daynames[2][8] = {
  35.     "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "",
  36.  
  37.     "son", "man", "tir", "ons", "tor", "fre", "lor", "",
  38.      };
  39. static char *monthnames[2][12] = {
  40.     "January", "February", "March", "April", "May", "June",
  41.     "July", "August", "September", "October", "November", "December",
  42.  
  43.     "januar", "februar", "mars", "april", "mai", "juni",
  44.     "juli", "august", "september", "oktober", "november", "desember" };
  45.  
  46. static FLAG initted = FALSE;    /* for current calendar */
  47. static int cal_month;
  48. static int cal_year;
  49.  
  50. static int cal_start = 0;    /* starting day of week, 0 = Sunday */
  51.  
  52. void D_Calendar();        /* void */
  53. void D_MakeConsistent();    /* int *yearptr, int *monptr */
  54.  
  55. /* ------------------------------------------------------------ */
  56.  
  57. /* Create and insert a calendar. */
  58.  
  59. void
  60. DCal()
  61.     {
  62.     struct tm t;
  63.  
  64.     if (!initted) {
  65.         initted = TRUE;
  66.         DNow(&t);
  67.         cal_month = t.tm_mon;
  68.         cal_year = t.tm_year;
  69.         }
  70.     if (!isuarg) ;
  71.     else if (uarg < 100) {
  72.         cal_month = uarg;
  73.         }
  74.     else if (uarg < 10000) {
  75.         cal_year = uarg;
  76.         }
  77.     else    {
  78.         cal_year = uarg % 10000;
  79.         cal_month = uarg / - 1;
  80.         }
  81.     D_MakeConsistent(&cal_year, &cal_month);
  82.     D_Calendar();
  83.     uarg = 0;
  84.     }
  85.  
  86.  
  87. /* ------------------------------------------------------------ */
  88.  
  89. /* Change the calendar by NUM months. */
  90.  
  91. void
  92. DMove(num)
  93.     int num;
  94.     {
  95.     struct tm t;
  96.  
  97.     if (!initted) {
  98.         initted = TRUE;
  99.         DNow(&t);
  100.         cal_month = t.tm_mon;
  101.         cal_year = t.tm_year;
  102.         }
  103.     cal_month += num;
  104.     D_MakeConsistent(&cal_year, &cal_month);
  105.     D_Calendar();
  106.     }
  107.  
  108.  
  109. /* ------------------------------------------------------------ */
  110.  
  111. /* Advance the calendar by UARG months. */
  112.  
  113. void
  114. DNext()
  115.     {
  116.     if (!isuarg) uarg = 1;
  117.     DMove(uarg);
  118.     uarg = 0;
  119.     }
  120.  
  121.  
  122. /* ------------------------------------------------------------ */
  123.  
  124. /* Return the current date and time in TPTR. */
  125.  
  126. void
  127. DNow(tptr)
  128.     struct tm *tptr;
  129.     {
  130.     time_t now;
  131.  
  132. #if defined(SYSMGR)
  133.     JGetDate(&tptr->tm_year, &tptr->tm_mon, &tptr->tm_mday);
  134. #else
  135.     now = time(NULL);
  136.     *tptr = *localtime(&now);
  137.     tptr->tm_year += 1900;
  138. #endif
  139.     }
  140.  
  141.  
  142. /* ------------------------------------------------------------ */
  143.  
  144. /* Return the day of the week (0 = Sunday) for the supplied day number. */
  145.  
  146. int
  147. DOW(day)
  148.     long day;
  149.     {
  150.     return((day + 0) % 7);
  151.     }
  152.  
  153.  
  154. /* ------------------------------------------------------------ */
  155.  
  156. /* Rewind the calendar by UARG months. */
  157.  
  158. void
  159. DPrev()
  160.     {
  161.     if (!isuarg) uarg = 1;
  162.     DMove(-uarg);
  163.     uarg = 0;
  164.     }
  165.  
  166.  
  167. /* ------------------------------------------------------------ */
  168.  
  169. /* Setup the day of week start (0=sunday). */
  170.  
  171. void
  172. DSetup(weekstart)
  173.     int weekstart;
  174.     {
  175.     cal_start = weekstart;
  176.     }
  177.  
  178.  
  179. /* ------------------------------------------------------------ */
  180.  
  181. /* Convert the day number to a date.  CAL is 0=360 day, 2=365 day,
  182. other=actual.  Should do sanity checking, but... */
  183.  
  184. void
  185. DToDate(tptr, day, cal)
  186.     struct tm *tptr;
  187.     long day;
  188.     int cal;
  189.     {
  190.     long dn;
  191.     long ltmp;
  192.  
  193.     memset((char *)tptr, NUL, sizeof(*tptr));
  194.  
  195.     switch (cal) {
  196.  
  197.     case 0:
  198.         tptr->tm_year = day / 360;
  199.         tptr->tm_mon = (day % 360) / 30;
  200.         tptr->tm_mday = (day % 30) + 1;
  201.         break;
  202.  
  203.     case 2:
  204.         tptr->tm_year = day / 365;
  205.         day %= 365;
  206.         for (tptr->tm_mon = 0;
  207.             day >= mdays[tptr->tm_mon + 1];
  208.             tptr->tm_mon++) ;
  209.         tptr->tm_mday = day - mdays[tptr->tm_mon] + 1;
  210.         break;
  211.  
  212.     default:
  213. /* Divide the day number by 365.2422 to get real close to the correct
  214. year.  We must do this with ints, so multiply by 10,000 and divide by
  215. 3652422.  But our day numbers range up to 9999 * 366 (or so) =
  216. 3,600,000.  Multiplying by 10,000 exceeds a 32-bit int.  We have to
  217. reduce the 10,000 by a factor of 20 or so in order not to overflow.
  218.  
  219. If we call the orgininal number 365.2425 and so get 10,000 and
  220. 3652425, we can remove a factor of 25 and obain 400 and 146,097.  This
  221. works but is incorrect to the tune of 3 parts in (roughly) 3,000,000
  222. or 1 in 1,000,000.  As there are only about 2,500 leap year days that
  223. can foul things up, we are still close enough.  Later steps will
  224. correct any error. */
  225.  
  226.         ltmp = day * 400;
  227.         ltmp /= 146097;
  228.  
  229. /* Now the corrections start.  First, make sure that we are before the
  230. correct year. */
  231.  
  232.         tptr->tm_year = ltmp - 2;
  233.  
  234. /* Now, count up until we get to the correct year. */
  235.  
  236.         tptr->tm_mon = 0;
  237.         tptr->tm_mday = 1;
  238.         for (dn = 0; dn < day; tptr->tm_year++) {
  239.             dn = DToDayN(tptr, 1);
  240.             if (dn == day) return;    /* done! */
  241.             }
  242.         tptr->tm_year -= 2;
  243.  
  244. /* We now have the correct year. On to the month and day. */
  245.  
  246.         day -= DToDayN(tptr, 1);
  247.  
  248.         if (day < mdays[1]) {
  249.             tptr->tm_mday = day + 1;    /* Jan */
  250.             return;
  251.             }
  252.         else if (day < mdays[2]) {
  253.             tptr->tm_mon = 1;
  254.             tptr->tm_mday = day - mdays[1] + 1; /* Feb 28 */
  255.             return;
  256.             }
  257.  
  258. /* It is either Feb 29 (if we have a leap year), or some day after that */
  259.  
  260. /* See if we are a leap year. */
  261.         if (tptr->tm_year / 4 == 0 &&
  262.             (tptr->tm_year / 100 != 0 ||
  263.              tptr->tm_year / 400 == 0)) {    /* leap year */
  264.             if (day == mdays[2]) {
  265.                 tptr->tm_mon = 1;
  266.                 tptr->tm_mday = 29;
  267.                 return;
  268.                 }
  269.             day--;        /* treat as regular day */
  270.             }
  271.  
  272.         for (tptr->tm_mon = 2;
  273.             day >= mdays[tptr->tm_mon + 1];
  274.             tptr->tm_mon++) ;
  275.         tptr->tm_mday = day - mdays[tptr->tm_mon] + 1;
  276.         break;
  277.         }
  278.     }
  279.  
  280.  
  281. /* ------------------------------------------------------------ */
  282.  
  283. /* Convert the date to a day number and return the day number.  CAL is
  284. 0=360 day, 2=365 day, other=actual. */
  285.  
  286. long
  287. DToDayN(tptr, cal)
  288.     struct tm *tptr;
  289.     int cal;
  290.     {
  291.     long tmp;
  292.     int y;
  293.     int m;
  294.     int d;
  295.  
  296.     y = tptr->tm_year;
  297.     m = tptr->tm_mon;
  298.     d = tptr->tm_mday;
  299.  
  300.     D_MakeConsistent(&y, &m);
  301.     if (d < 1 || d > 31) d = 1;
  302.  
  303.     switch (cal) {
  304.  
  305.     case 0:
  306.         tmp = (360 * (long)y) + 30 * m + d - 1;
  307.         break;
  308.  
  309.     case 2:
  310.         tmp = (365 * (long)y) + mdays[m] + d - 1;
  311.         break;
  312.  
  313.     default:
  314.         tmp = (365 * (long)y) + mdays[m] + d - 1;
  315.  
  316.             /* Jan and Feb get previous year's leap year counts */
  317.         if (m <= 1) y--;
  318.  
  319.         tmp += y / 4;        /* add leap years */
  320.         tmp -= y / 100;        /* subtract non-leap cents. */
  321.         tmp += y / 400;        /* add back 400 years */
  322.         break;
  323.         }
  324.     return(tmp);
  325.     }
  326.  
  327.  
  328. /* ------------------------------------------------------------ */
  329.  
  330. /* Display a calendar, given a date. */
  331.  
  332. #if !defined(NOCALC)
  333. void
  334. DXCal(tptr)
  335.     struct tm *tptr;
  336.     {
  337.     initted = TRUE;
  338.  
  339.     cal_month = tptr->tm_mon;
  340.     cal_year = tptr->tm_year;
  341.  
  342.     D_MakeConsistent(&cal_year, &cal_month);
  343.     D_Calendar();
  344.     }
  345. #endif
  346.  
  347.     
  348. /* ------------------------------------------------------------ */
  349.  
  350. /* Display the calendar. */
  351.  
  352. void
  353. D_Calendar()
  354.     {
  355.     struct tm t;
  356.     char buf[LINEBUFFSIZE];
  357.     int cnt;
  358.     int start;
  359.     int numdays;
  360.     long dayn;
  361.  
  362.     if (!FMakeSys(SYS_CAL, TRUE)) return;
  363.  
  364.     xsprintf(buf, "%s %4d\n", monthnames[c.g.language][cal_month], cal_year);
  365.     BInsSpaces((CAL_WIDTH - strlen(buf) - 1) / 2);
  366.     BInsStr(buf);
  367.  
  368.     for (cnt = 0; cnt < 7; cnt++) {
  369.         xsprintf(buf, " %s ", daynames[c.g.language][(cnt + cal_start) % 7]);
  370.         BInsStr(buf);
  371.         }
  372.     BInsChar(NL);
  373.  
  374.     t.tm_year = cal_year;
  375.     t.tm_mon = cal_month;
  376.     t.tm_mday = 1;
  377.     dayn = DToDayN(&t, 1);
  378.     start = DOW(dayn);
  379.  
  380.     t.tm_mon++;
  381.     numdays = DToDayN(&t, 1) - dayn;
  382.  
  383.     BInsSpaces(5 * start);
  384.     for (cnt = 1; cnt < numdays + 1; cnt++) {
  385.         xsprintf(buf, "  %2d%c", cnt,
  386.             (cnt + start + cal_start) % 7  == 0 ? NL : SP);
  387.         BInsStr(buf);
  388.         }
  389.     BMoveBy(-1);
  390.     BCharDelete(1);
  391.     BInsChar(NL);
  392.     BMoveToStart();
  393.     }
  394.  
  395.  
  396. /* ------------------------------------------------------------ */
  397.  
  398. /* Bring the month into the range 1-12 and adjust the year
  399. accordingly. */
  400.  
  401. void
  402. D_MakeConsistent(yearptr, monptr)
  403.     int *yearptr;
  404.     int *monptr;
  405.     {
  406.     while (*monptr > 11) {
  407.         (*monptr) -= 12;
  408.         (*yearptr)++;
  409.         }
  410.     while (*monptr < 0) {
  411.         (*monptr) += 12;
  412.         (*yearptr)--;
  413.         }
  414.     if (*yearptr > 9999) {
  415.         *monptr = 11;
  416.         *yearptr = 9999;
  417.         }
  418.     if (*yearptr < 1583) {
  419.         *monptr = 0;
  420.         *yearptr = 1583;
  421.         }
  422.     }
  423.  
  424.  
  425. /* end of DATE.C -- Calendar Routines */
  426.